#! /bin/bash

# mk_initrd - create the inital ramdisk images
# usage: see below usage() or call with -h
#
# Copyright (C) 2003 SuSE Linux AG, Nuernberg, Germany
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
# USA.


# Version 1.41
#
# Author: Steffen Winterfeldt <wfeldt@suse.de>
#         Susanne Oberhauser  <froh@suse.de>
#         Bernhard Kaindl     <bk@suse.de>
#
# (c) 1999-2003 SuSE Linux AG
# (c) 1999 Heiko Eifeldt bugfix, add module parameter passing
# (c) 2000 Karsten Keil   option and kernel 2.4 support
#
# ChangeLog:
#
# 27/03/2003:   v1.41
# - use $root_dir for /etc/fstab when getting rootfstype
# - add -D <interface> option to make initrd use dhcp and nfs-root
# 16/11/2002:   v1.40
# - use $root_dir for checking if the initrd needs lib64 libs and ld.so
# 14/11/2002:   v1.39
# - more inodes are needed in mk_initrd if libc is added (#20822)
# 10/11/2002:   v1.38
# - initialize zfcp with module parameter instead of
#   /proc/scsi/zfcp/add_map, so the disks are available without echo
#   "scsi add-single-device>/proc/scsi/scsi" after module load. (#20709)
# 08/9/2002:    v1.37
# - fix missing /lib/ld64.so on s390x
# - if zfcp is set up but not configured copy current setup to zfcp.conf
# - handle zipl like lilo: on success tell the admin to call zipl!
# - fix adding of dasd disciplines to check which disciplines are needed
# - fix remaining references to the module dasd to use dasd_mod
# - s390/s390x: show architecture when showing the kernel version
# 27/9/2002:    v1.36
# - mount proc if not mounted and unmount it at cleanup time before exit
# - avoid printing overlong files during initrd creation process and
#   format the output in the same change.
# - s390: if dasd_mod has no options in modules.conf, use the env set by
#   the kernel parameter to find the needed dasds
# 24/9/2002:    v1.35
# - remove explicit inclusion of module dasd.o, which gives the freedom to
#   rename it to dasd_mod.o some day (soon).
# 13/9/2002:    v1.34
# - fix module dependency handling
# - fix zfcp handling
# - fix mod_dasd support
# 12/9/2002:    v1.33
# - resolve module dependencies for each kernel
# 03/9/2002:    v1.32
# - use lib64 on 64-bit systems
# - use /var/tmp instead of /tmp (/tmp may be tmpfs)
# - use new ash builtin 'createpartitiondevs' to create missing devs
# - made root-on-lvm work by telling the kernel the right device
# 27/8/2002:    v1.31
# - use hwinfo to get unknown vga mode sizes
# - create missing devices in pivot_root case
# - fix jfs fsck
# - resolve module dependencies
# - match full module name when searching for module parameters
# 21/8/2002:    v1.30
# - uuid/label: detect real device with fsck hack
# - pivot_root: almost completely rewritten, now honors root= kernel
#   option
# 19/8/2002:    v1.29
# - fixed use_pivot_root:
# - use_pivot_root for root device specified via LABEL= or UUID= in
#   root_dir/etc/fstab
# - scan both /proc/mounts (for LVM check) and /etc/fstab (for LABEL=...)
# - make existing checks use the results of this scan
#
# 15/7/2002:	v1.28
#  - explicit -t ext2 for mounting initrd
#  - add all md devices, not just md0 (reported by tobias@wolf.gl)
#
# 12/7/2002:	v1.27
#  - ignore comments in lilo.conf
#
# 13/6/2002:	v1.26
#  - nicer output
#  - don't do pivot_root for ext3, too dangerous with newer kernels
#    (and obsoleted by andrea's ext3 reordering patch)
#
# 25/3/2002:	v1.26
#  - handle splash properly if using a different root dir
#
# 21/3/2002:	v1.25
#  - add /sbin/fsck.jfs if jfs.o is loaded
#  - added '-t' option to use a different tmp directory
#
# 25/2/2002:	v1.24
#  - there might be more than one module with the same name; we take
#    just the first one we find, assuming they are identical anyway
#
# 13/2/2002:    v1.23
#  - use default kernel names on alpha.
#
# 14/1/2002:	v1.22
#  - INITRD_MODULES has been moved to /etc/sysconfig/kernel
#
# 13/9/2001:	v1.21
#  - added oem resize support
#  - added support for splash image sizes
#
# 10/9/2001:	v1.20
#  - new header format for splash picture
#
# 07/9/2001:    v1.19
#  - add "splashanim" feature.
#
# 14/8/2001:	v1.18
#  - run 'raidautorun' only if raid is used
#  - add xor module if missing
#  - hint to run lilo
#
# 13/8/2001:	v1.17
#  - run 'raidautorun' after loading all modules
#    (note: raidautorun is a ash/sash builtin)
#
# 14/5/2001:	v1.16
#  - automagically add lvm-mod.o
#
# 10/5/2001:	v1.15
#  - copy ld-*so* to initrd, not ld-2.2.so
#  - make it work in chroot environment
#
# 7/5/2001:	v1.14
#  - drop vmlinuz_24 (no longer exists)
#
# 5/3/2001:	v1.13 Stefan Rauch <srauch@suse.de>
#  - automatically adjust initrd size
#
# 13/1/2001:	v1.12
#  - continue with next kernel/initrd on errors
#  - create initrd even if modules are missing
#    (exit code 9 is returned in these cases)
#  - keep old initrd if a new one could not be made
#
# 18/12/2000:   v1.11 Karsten Keil <kkeil@suse.de>
#  - adapt changes from pre 7.1
#  - make it working on new 2.4 module tree
#
# 18/8/2000:    v1.10 Karsten Keil <kkeil@suse.de>
#  - support for 2.4 kernel versions
#  - optional parameter for easy use with other kernel versions
#
#  6/7/2000:	v1.09
#  - started log
#  - use get_kernel_version instead of file
#  - increased initrd size to 2000k
#

#
# Print usage and exit
#
usage() {
	cat<<EOM
	mk_initrd creates initial ramdisk images for booting linux
                  with enviroments which need loading modules before
                  mounting the root device (e.g SCSI controller)

        mk_initrd [options] [root_dir]

        options:
          -h               This Text.
          -k "kernel list" list of kernel images for which initrd files
                           are created (relative to boot_dir)
                           defaults to "vmlinuz vmlinuz.shipped"
          -i "initrd list" list of file names (relativ to boot_dir) for
                           the initrd; position have match to "kernel list"
                           defaults to "initrd initrd.shipped"
          -m "module list" modules to include in initrd, defaults to
                           INITRD_MODULES variable in /etc/sysconfig/kernel
          -b boot_dir      boot dir, defaults to "/boot"
          -d root_device   root device, defaults to the device from which
                           the root_dir is mounted; overwrites the rootdev
                           enviroment variable if set
	  -s size          Add splash animation and bootscreen to initrd.
	  -o file          Add OEM resize support.
	  -t tmp_dir       tmp dir, defaults to "/tmp"
	  -D interface     run dhcp on the specified interface

        root_dir:          the directory the root partition is mounted to
                           defaults to "/"
EOM
	case $arch in
	    s390*)
		cat <<EOF

If the zfcp module is configured in root_dir/etc/zfcp.conf, mk_initrd
will add zfcp support to the initrd as well.

EOF
		;;
	esac
	exit
}

# You can specify the root device via the environment variable rootdev (e.g.
# "rootdev=/dev/hda mk_initrd").

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# general configurable parameters

# the kernel images to use; must be in $boot_dir
kernels_default="vmlinuz vmlinuz.shipped"
# initial ram disks (corresponding to $kernels); dto. in $boot_dir
initrds_default="initrd initrd.shipped"

kernels=""
initrds=""
modules=""
boot_dir=""
splash="auto"
oem=""

# architecture dependend changes:
arch=`uname -m`
arch=${arch/ppc64/ppc}
arch=${arch/s390x/s390}
case $arch in
    ppc)
	kernels_default="vmlinux"
	initrds_default="initrd"
	test -d /proc/iSeries && kernels_default="vmlinux64"
	;;
    s390)
	kernels_default="kernel/image"
	initrds_default="initrd"
	splash=off
	;;
esac

while getopts :hk:i:m:b:d:o:s:t:D: a ; do
	case $a in
		\:|\?)	case $OPTARG in
				k)	echo "-k requires kernel list parameter"
					;;
				i)	echo "-i requires initrd list parameter"
					;;
				m)	echo "-m requires module list parameter"
					;;
				b)	echo "-b requires boot dir parameter"
					;;
				d)	echo "-d requires root device parameter"
					;;
				s)	echo "-s requires image size(s)"
					;;
				o)	echo "-o requires oem grow script"
					;;
				t)	echo "-t requires tmp dir parameter"
					;;
				D)	echo "-D requires dhcp interface parameter"
					;;
				*)  echo "Unknown option: -$OPTARG"
					echo "Try mk_initrd -h"
					;;
			esac
			exit 1
			;;
		k)	kernels=$OPTARG
			;;
		i)	initrds=$OPTARG
			;;
		m)	modules=$OPTARG
			;;
		b)	boot_dir=$OPTARG
			;;
		d)	rootdev=$OPTARG
			;;
		o)	oem=$OPTARG
			;;
		s)	splash=$OPTARG
			;;
		t)	tmp_dir=$OPTARG
			;;
		D)	dhcp_interface=$OPTARG
			dhcp_interface=${dhcp_interface#/dev/}
			use_pivot_root=1
			;;
		h)	usage
			;;
	esac
done
shift `expr $OPTIND - 1`

[ -n "$1" ] && root_dir="$1"
[ "$root_dir" ] || root_dir=/

# handle splash screen
[ "x$splash" = xoff ] && splash=
if [ "x$splash" = xauto ] ; then
    splash=
    vgascan=/dev/null
    test -f $root_dir/etc/lilo.conf && vgascan="$vgascan $root_dir/etc/lilo.conf"
    test -f $root_dir/boot/grub/menu.lst && vgascan="$vgascan $root_dir/boot/grub/menu.lst"
    for vga in `cat $vgascan | sed -n -e '/^[ 	]*#/d' -e 's/^.*[ 	]*vga[ 	]*=[ 	]*\([0-9a-fA-FxX]*\).*$/\1/p'` ; do
	splashsize=
	case $vga in
	    785|786|0x311|0x312) splashsize=640x480   ;;
	    788|789|0x314|0x315) splashsize=800x600   ;;
	    791|792|0x317|0x318) splashsize=1024x768  ;;
	    794|0x31a|0x31A)     splashsize=1280x1024 ;;
	    795|0x31b|0x31B)     splashsize=1280x1024 ;;
	    *)
		vgahex=`printf 0x%04x "$vga"`
		splashsize=`hwinfo debug=0 -all +bios.vbe | sed -ne 's/^.*Mode '$vgahex': \([^ ][^ ]*\) .*$/\1/p' 2>/dev/null`
		;;
	esac
	test -n "$splashsize" && test "x${splash/$splashsize/}" = "x$splash" && splash="$splash,$splashsize"
    done
    splash=${splash#,}
fi

# check that $kernels and $initrds are both set or both unset
if [ -n "$kernels" ] ; then
   if [ -z "$initrds" ] ; then
      echo "you have to specify -k and -i or none"
      exit 1
   fi
fi

if [ -z "$kernels" ] ; then
   if [ -n "$initrds" ] ; then
      echo "you have to specify -k and -i or none"
      exit 1
   fi
fi

# ppc magic: kernel can be either vmlinux or vmlinuz
if [ "$arch" = ppc -a "$kernels_default" = vmlinux ] ; then
  [ ! -f "$boot_dir/vmlinux" ] && kernels_default="vmlinuz"
fi

# the kernel images to use; must be in $boot_dir
[ -z "$kernels" ] && kernels="$kernels_default"

# initial ram disks (corresponding to $kernels); dto. in $boot_dir
[ -z "$initrds" ] && initrds="$initrds_default"

kc=`echo $kernels |wc -w`
ic=`echo $initrds |wc -w`
if [ $kc != $ic ] ; then
    echo "item count in -k and -i lists have to match"
    exit 1
fi


# *full* paths
[ -z "$boot_dir" ] && boot_dir=/boot

# *full* paths
[ -z "$tmp_dir" ] && tmp_dir=/var/tmp


static_shell=/bin/ash.static
static_insmod=/sbin/insmod.static

bootsplash_picture_dir="$root_dir/usr/share/splash/themes/current"
# maximum initrd size
image_blocks=10000
image_inodes=2000

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# should be nothing to change below...

PATH=/sbin:/usr/sbin:$PATH

tmp_mnt=$tmp_dir/mnt$$
tmp_mnt_small=${tmp_mnt}_small
tmp_msg=$tmp_dir/msg$$
tmp_modconf=$tmp_dir/modconf$$
lx_rc=$tmp_mnt/linuxrc
is_mounted=
is_mounted_small=

umount_proc() {
  [ "$mounted_proc" ] && umount $mounted_proc
  mounted_proc=
}

clean_up () {
  rm -f $tmp_modconf
  [ "$is_mounted" ] && umount $tmp_mnt
  is_mounted=
  [ "$is_mounted_small" ] && umount $tmp_mnt_small
  is_mounted_small=
  rm -f $tmp_initrd $tmp_initrd.gz $tmp_msg
  rm -f $tmp_initrd_small $tmp_initrd_small.gz
  [ -d $tmp_mnt ] && rmdir $tmp_mnt
  [ -d $tmp_mnt_small ] && rmdir $tmp_mnt_small
}

enable_module () {
  modules="$modules $1"
  echo -e "\nNote: If you want to add $2 support for later mkinitrd"
  echo "calls where possibly no $2 is found, add $1"
  echo 'to INITRD_MODULES in /etc/sysconfig/kernel'
}

error () {
  echo "$2"
  clean_up
  umount_proc
  exit $1
}

oops () {
  echo "$2"
  clean_up
}

# working directories
tmp_initrd=$root_dir/$tmp_dir/initrd$$
tmp_initrd_small=${tmp_initrd}_small

###################################################################

mounted_proc=
if [ ! -r /proc/mounts ]; then
  mounted_proc=/proc
  mount -t proc proc $mounted_proc
fi

if [ -z "$rootdev" ] ; then
  # no rootdev specified, get current root from /etc/fstab
  while read fstab_device fstab_mountpoint fstab_type fstab_options dummy ; do
    test "$fstab_mountpoint" = "/" && {
      rootdev="$fstab_device"
      rootfstype="$fstab_type"
      break
    }
  done < <( sed -e '/^[ 	]*#/d' < $root_dir/etc/fstab)
else
  # get type from /etc/fstab or /proc/mounts (actually not needed)
  x1=`cat $root_dir/etc/fstab /proc/mounts 2>/dev/null | grep -E "$rootdev[[:space:]]" | tail -1`
  rootfstype=`echo $x1 | cut -f 3 -d " "`
fi

if test -z "$dhcp_interface" ; then
    test -z "$rootdev" && error 1 "no '/' mountpoint specified in $root_dir/etc/fstab."
else
    rootdev=
    rootfstype=nfs
fi

realrootdev="$rootdev"
case "$rootdev" in
  LABEL=*|UUID=*)
    use_pivot_root=1
    # get real root via fsck hack
    realrootdev=`fsck -N "$rootdev" | sed -ne '2s/.* \/dev/\/dev/p' | sed -e 's/  *//g'`
    test -n "$realrootdev" || error 1 "could not expand $rootdev to real device."
    ;;
esac

# check if the root device is an lvm device
root_lvm=0
if [ -n "$realrootdev" -a -b "$realrootdev" ] ; then
    major=`ls -l "$realrootdev" | sed -e "s/.* \\([0-9]\+\\), *[0-9]\+.*/\\1/"`
    [ "$major" -ne 58 ] || root_lvm=1
fi

# take the static utilities from root_dir, if they are present
# there. why so???
if [ "$root_dir" != / ] ; then
  LD_LIBRARY_PATH=$root_dir/usr/lib
  PATH=$root_dir/usr/bin:$PATH
  [ -x "$root_dir$static_shell" ] && static_shell="$root_dir$static_shell"
  [ -x "$root_dir$static_insmod" ] && static_insmod="$root_dir$static_insmod"
fi

###################################################################
#
# zFCP
#
cat /proc/modules | grep -q "^zfcp" && do_zfcp=1

#
# If the initial zfcp setup is not done, do it (important for
# installation):
#
test "$do_zfcp" -a ! -s $root_dir/etc/zfcp.conf && {
    fcpconf=`cat /proc/scsi/zfcp/map`
    test -n "$fcpconf" && {
	echo "$fcpconf" > $root_dir/etc/zfcp.conf
	chmod 644 $root_dir/etc/zfcp.conf
    }
}

zfcp_conf_contents=""
test -f $root_dir/etc/zfcp.conf && zfcp_conf_contents=$(sed -e '
s,#.*,,
/^[[:blank:]]*$/d
' $root_dir/etc/zfcp.conf)

test -n "$zfcp_conf_contents" && do_zfcp=1

###################################################################
#
# DASD
#
cat /proc/modules | grep -q -e "^dasd" && do_dasd=1

# the dasd module has to be configured in root_dir/etc/zipl.conf or
# with a parameter in modules.conf

test -f $root_dir/etc/zipl.conf && {

    # check for zipl boot parameters with dasd= and check for
    # parameters without dasd=.  if both are present, warn below.

    grep -q '^[[:space:]]*parameters=.*dasd=' $root_dir/etc/zipl.conf \
	&& zipl_conf_with_dasd=1

    grep '^[[:space:]]*parameters=' $root_dir/etc/zipl.conf \
	| grep -qv 'dasd=' && zipl_conf_no_dasd=1
}

grep -q '^[[:space:]]*options[[:space:]]\+dasd_mod' $root_dir/etc/modules.conf && dasd_modules_conf=1

# if dasd= is mentioned in zipl.conf, assume dasd module usage.  the
# mk_initrd will create an initrd without dasd module, if the dasd
# support is compiled into the kernel.
test "$zipl_conf_with_dasd" && do_dasd=1

# if it is mentioned in modules.conf, assume it should be used:
test "$dasd_modules_conf" && do_dasd=1

###################################################################

x="\"$rootdev\""
test -n "$dhcp_interface" && x="nfs-root"
test "$rootdev" != "$realrootdev" && x="$x ($realrootdev)"
echo "using $x as root device (mounted on \"$root_dir\" as \"$rootfstype\")"

# get INITRD_MODULES as set by YaST
[ -f "$root_dir/etc/sysconfig/kernel" ] && . $root_dir/etc/sysconfig/kernel

[ -z "$modules" ] && modules="$INITRD_MODULES"

###################################################################
# add modules required by features
if [ "$root_lvm" = 1 ] ; then
  # add lvm-mod if missing
  echo " $modules " | grep -q " lvm-mod " || modules="lvm-mod $modules"
fi

# check if an initrd is needed at all.
#
# on s390 the initrd is always needed as long as we don't set the
# initrd flag in /etc/zipl.conf with YaST.
[ "$modules" -o "$root_lvm" = 1 -o "$use_pivot_root" = 1 -o -n "$oem" -o -n "$splash" -o "$arch" = s390 ] || {
  ( cd $root_dir$boot_dir ; rm -f $initrds )
  error 0 "no initrd required"
}

###################################################################
# synchronize $do_* and $has_* flags with $modules
do_raid=
do_raid5=
has_xor=
has_jfs=
has_nls=
has_qdio=
for i in $modules ; do
  case $i in
    raid[01]|linear|multipath) do_raid=1 ;;
    raid5) do_raid=1 do_raid5=1 ;;
    zfcp) do_zfcp=1 ; has_zfcp=1;;
    sd_mod) has_sd_mod=1;;
    dasd_mod) do_dasd=1 ;;
    xor) has_xor=1 ;;
    jfs) has_jfs=1 ;;
    dasd_fba_mod) has_dasd_fba=1 ;;
    dasd_eckd_mod) has_dasd_eckd=1 ;;
    dasd_diag_mod) has_dasd_diag=1 ;;
    nls_iso8859-1) has_nls=1 ;;
    qdio) has_qdio=1 ;;
  esac
done

###################################################################
# expand module dependencies

# raid5 needs xor
[ "$do_raid5" -a ! "$has_xor" ] && modules="xor $modules"

# jfs needs nls_iso8859-1
[ "$has_jfs" -a ! "$has_nls" ] && modules="$modules nls_iso8859-1"

# zfcp needs qdio
[ "$do_zfcp" -a ! "$has_qdio" ] && modules="qdio $modules"

# add dasd disciplines
test "$do_dasd" && {
  test -z "$has_dasd_eckd" && grep -q ECKD /proc/dasd/devices && {
     echo -e "\nFound ECKD dasd, adding dasd eckd discipline!"
     enable_module dasd_eckd_mod 'ECKD dasd'
  }
  test -z "$has_dasd_fba"  && grep -q FBA  /proc/dasd/devices && {
     echo -e "\nFound FBA dasd, adding dasd fba discipline!"
     enable_module dasd_fba_mod  'FBA dasd'
  }
  test -z "$has_dasd_diag" && grep -q DIAG /proc/dasd/devices && {
     echo -e "\nFound DIAG dasd, adding dasd diag discipline!"
     enable_module dasd_diag_mod 'DIAG dasd'
  }
}

# add zfcp modules
test "$do_zfcp" && {
    test "$has_zfcp" || modules="zfcp $modules"
    test "$has_sd_mod" || modules="$modules sd_mod"
}

###################################################################
# more sanity checks after all variables and $modules are synchronized:

# dasd
test "$do_dasd" && {
    test "$zipl_conf_with_dasd" -o "$dasd_modules_conf"  || {
	error 1 "\
dasd module required but no dasd configuration found in
root_dir/etc/zipl.conf and root_dir/etc/modules.conf"
    }

    test "$zipl_conf_with_dasd" -a "$zipl_conf_no_dasd" && {
	echo "\
warning: there are some parameter definitions without dasd parameter
in root_dir/etc/zipl.conf:"

	# show all sections with paramenters
	grep -n -e '^[[:space:]]*\[' -e '^[[:space:]]*parameters=' $root_dir/etc/zipl.conf |
	grep --before-context=1  '^[[:digit:]]*:[[:space:]]*parameters='
	test "$dasd_modules_conf" && {
	    echo "for those without dasd parameter, the parmline from root_dir/etc/modules.conf rules"
	}
    }
}

# zFCP
test "$do_zfcp" = 1 -a -z "$zfcp_conf_contents" && {
    error 1 "zfcp module loaded but root_dir/etc/zfcp.conf empty.
don't know how to configure zfcp in initrd.

you can save the current configuration with this command:

    cat /proc/scsi/zfcp/map >> root_dir/etc/zfcp.conf
"
}

###################################################################
need_libc=
[ "$root_lvm" = 1 -o -n "$oem" -o "$use_pivot_root" -o "$has_jfs" -o "$do_zfcp" ] && need_libc=1

if [ "$need_libc" ] ; then
  static_shell="$root_dir/bin/ash"
  static_insmod="$root_dir/sbin/insmod"
  image_inodes=8000
fi

lib=lib
case $arch in
  x86_64) lib=lib64 ;;
  s390)   [ -s $root_dir/lib/ld64.so.1 ] && lib=lib64 ;;
esac

# put the initrds in an array
initrd_a=($initrds)

exit_code=0

kernel_idx=0
for k in $kernels ; do

  # the kernel
  kk="$root_dir$boot_dir/$k"
  kk="${kk/#\/\///}"

  if [ -f "$kk" ] ; then

    # the kernel version
    vv=`/sbin/get_kernel_version $kk`

    # the initrd
    ii="$root_dir$boot_dir/${initrd_a[$kernel_idx]}"
    ii="${ii/#\/\///}"

    echo
    echo "creating initrd \"$ii\" for kernel \"$kk\""
    echo -n "(version $vv)"
    [ $arch = s390 ] && echo " ($HOSTTYPE)"
    echo

    [ -d "$root_dir/lib/modules/$vv/misc" ] || \
    [ -d "$root_dir/lib/modules/$vv/kernel" ] || {
      oops 2 "no version \"$vv\" modules found"
      continue
    }

    # create an empty initrd
    mkdir $tmp_mnt || error 1 "could not create temporary directory"
    dd if=/dev/zero of=$tmp_initrd bs=1k count=$image_blocks 2>/dev/null
    mke2fs -q -F -b 1024 -m 0 -N $image_inodes $tmp_initrd 2>/dev/null 1>&2
    tune2fs -i 0 $tmp_initrd >/dev/null 2>&1

    # mount it
    mount -t ext2 -oloop $tmp_initrd $tmp_mnt 2>/dev/null || {
      if [ -f /lib/loop.o ] ; then
        insmod /lib/loop.o
        mount -t ext2 -oloop $tmp_initrd $tmp_mnt 2>/dev/null || {
          error 3 "failed to mount image"
        }
      else
        error 3 "failed to mount image"
      fi
    }
    is_mounted=1

    # fill the initrd
    rmdir $tmp_mnt/lost+found
    mkdir $tmp_mnt/{bin,dev}
    case $arch in
	s390*) initrd_devices=$root_dir/dev/{zero,null,ram0,ram1,ram2,ram,ramdisk,console,md*};;
	*) initrd_devices=$root_dir/dev/{tty1,tty2,zero,null,ram0,ram1,ram2,ram,ramdisk,fb0,console,md*};;
    esac
    eval cp -a $initrd_devices $tmp_mnt/dev
    cp $static_shell $tmp_mnt/bin/sh 2>/dev/null || error 4 "no static shell"
    cp $static_insmod $tmp_mnt/bin/insmod 2>/dev/null || error 5 "no static insmod"

    if [ "$need_libc" ] ; then
      mkdir -p $tmp_mnt/{lib,etc,proc,mnt}
      [ "$lib" != lib ] && mkdir -p $tmp_mnt/$lib
      echo 'none /proc proc defaults 0 0' > $tmp_mnt/etc/fstab
      cp -a $root_dir/dev/[ehs]d? $root_dir/dev/[ehs]d?[0-9]* $tmp_mnt/dev
      cp -a $root_dir/dev/dasd* $tmp_mnt/dev 2>/dev/null
      cp -a $root_dir/dev/{i2o,ida,cciss,rd} $tmp_mnt/dev 2>/dev/null
      cp -a $root_dir/$lib/ld* $tmp_mnt/$lib
      if [ $arch = s390 -a -s $tmp_mnt/lib64/ld64.so.1 ]; then
	mv $tmp_mnt/lib64/ld* $tmp_mnt/lib
      fi
      cp -a $root_dir/$lib/libc.so.6 $tmp_mnt/$lib
      cp -a $root_dir/$lib/libz.so.1* $tmp_mnt/$lib
      cp -a $root_dir/bin/{mount,umount} $tmp_mnt/bin
      if [ -z "$use_pivot_root" -a -b "$root_dir/$rootdev" ] ; then
	mkdir -p $tmp_mnt/${rootdev%/*}
	cp -a $root_dir/$rootdev $tmp_mnt/${rootdev%/*}
      fi
    fi

    if [ $root_lvm -eq 1 ] ; then
      echo " - LVM support"
      cp -a $root_dir/dev/lvm  $tmp_mnt/dev
      cp -a $root_dir/$lib/liblvm*.so* $tmp_mnt/$lib
      cp -a $root_dir/sbin/{vgscan,vgchange} $tmp_mnt/bin
      cp -a $root_dir/bin/cat $tmp_mnt/bin
    fi

    if [ -n "$oem" ] ; then
      echo " - OEM resize support"
      cp -a $root_dir/sbin/{sfdisk,resize_reiserfs} $tmp_mnt/bin
      cp -a $root_dir/bin/{cp,cat,sed} $tmp_mnt/bin
      cp -a $root_dir/usr/bin/expr  $tmp_mnt/bin
    fi

    if [ "$use_pivot_root" ] ; then
      echo " - pivot root support"
      cp -a $root_dir/sbin/pivot_root $tmp_mnt/bin
      cp -a $root_dir/bin/cat $tmp_mnt/bin
      echo '#! /bin/sh' > $tmp_mnt/bin/init
      echo 'echo initrd failed, goodbye...' >> $tmp_mnt/bin/init
      chmod 755 $tmp_mnt/bin/init
      mkdir -p $tmp_mnt/mnt
    fi

    if [ -n "$dhcp_interface" ] ; then
      echo " - using dhcp on $dhcp_interface"
      cp -a $root_dir/sbin/dhcpcd $tmp_mnt/bin
      cp -a $root_dir/usr/bin/killall $tmp_mnt/bin
      cp -a $root_dir/$lib/libnss_dns.so.* $tmp_mnt/$lib
      cp -a $root_dir/$lib/libresolv.so.* $tmp_mnt/$lib
      mkdir -p $tmp_mnt/var/lib/dhcpcd
    fi

    if [ "$has_jfs" ] ; then
      echo " - JFS recovery support"
      cp -a $root_dir/sbin/fsck $tmp_mnt/bin
      cp -a $root_dir/sbin/fsck.jfs $tmp_mnt/bin
      cp -a $root_dir/$lib/libuuid.so.* $tmp_mnt/$lib
      cp -a $root_dir/$lib/libext2fs.so.* $tmp_mnt/$lib
      cp -a $root_dir/$lib/libcom_err.so.* $tmp_mnt/$lib
    fi

    echo '#! /bin/sh' >$lx_rc
    echo >>$lx_rc
    echo "export PATH=/bin" >>$lx_rc
    echo >>$lx_rc

    chmod 755 $lx_rc

    # resolve module dependencies, individually for each kernel version
    # kernel version is $vv
    rm -f $tmp_modconf
    echo "depfile=$root_dir/lib/modules/$vv/modules.dep" >$tmp_modconf
    mods2=
    for mod in $modules ; do
      modlist=`/sbin/modprobe -C $tmp_modconf -v -n $mod 2>/dev/null | sed -ne 's#^/sbin/insmod.*/\(.*\)\.o.*#\1#p'`

      [ "$modlist" ] || modlist=$mod
      for i in $modlist ; do
        [ "$mods2" = "${mods2/ $i / }" ] && mods2="$mods2 $i "
      done
    done
    modules_res=`echo $mods2`

    # copy the modules to the initrd
    for i in $modules_res; do
      # Note: we rely on module names being unique here. While this is true
      # so far there _are_ modules that are just links to others with the
      # same name in different directories (pcmcia mods, for example). But
      # in this case it doesn't really matter which one we use.
      x=`cd $root_dir ; find lib/modules/$vv/ -name $i.o | head -1`
      if [ "$x" ] ; then
        tar -C $root_dir -cf - $x 2>/dev/null | tar -C $tmp_mnt -xpf - 2>/dev/null
        if [ $? != 0 ] ; then
          echo "$i: failed to add module \"/$x\""
          oops 6 "initrd too small"
          continue 2
        fi
        modparms=`grep "^[	]*options \<$i\>" "$root_dir"/etc/modules.conf`
        modparms="${modparms#* * }"
	if [ "$i" = dasd_mod -a -z "$modparms" ]; then
	  modparms='dasd=$dasd'
	fi
        if [ "$i" = zfcp -a -z "$modparms" ]; then
	  modparms="map=\"
$zfcp_conf_contents\""
	fi
	test -n "$modparms" && modparms=" $modparms"
        echo "echo 'Loading module $i$modparms ...'" >>$lx_rc
        echo " - insmod `printf %-19s "$i$modparms"` (${x#lib/modules/[^/]*/})"
        echo "insmod $i$modparms" >>$lx_rc
        echo >>$lx_rc
      else
        echo "$i: no such module"
        exit_code=9
#        oops 7 "no such module: $i"
#        continue 2
      fi
    done

    if [ "$do_zfcp" ] ; then
      echo " - zfcp support"
      cp -a --parents $root_dir/bin/cat       $tmp_mnt/
      cp -a --parents $root_dir/etc/zfcp.conf $tmp_mnt/
      cat >>$lx_rc <<EOF
echo "zfcp ..."
mount -n -tproc none /proc
cat /etc/zfcp.conf > /proc/scsi/zfcp/add_map
umount -n /proc
echo "done ..."

EOF
    fi

    if [ "$do_raid" ] ; then
      echo " - raidautorun"
      echo "echo \"raidautorun ...\" " >>$lx_rc
      echo "raidautorun" >>$lx_rc
      echo "echo \"done ...\" " >>$lx_rc
      echo >>$lx_rc
    fi

    if [ $root_lvm -eq 1 ] ; then
	# need dummy entry so fsck doesn't complain
	cat >>$lx_rc <<EOF
# scan for lvm devices
mount -n -tproc none /proc
vgscan
vgchange -a y
# set the right root device if user specified a lvm root
root=
for o in \`cat /proc/cmdline\` ; do
  case \$o in
    root=*) root="\$o" ;;
  esac
done
if test -n "\$root"; then
  echo "\$root" > /.root
  oifs="\$IFS"
  IFS="="
  read dummy rootdev < /.root
  IFS="\$oifs"
  rootdevn=\`devnumber \$rootdev 2>/dev/null\`
  test -n "\$rootdevn" -a "\$rootdevn" -ge 14848 -a "\$rootdevn" -lt 15104 && echo "\$rootdevn" > /proc/sys/kernel/real-root-dev
fi
umount -n /proc

EOF
    fi

    [ -n "$oem" ] && cat $oem >> $lx_rc

    if [ "$use_pivot_root" ] ; then
	cat >>$lx_rc <<EOF
# create missing devices
mount -n -tproc none /proc
createpartitiondevs
umount -n /proc

EOF
    fi

    if [ "$dhcp_interface" ] ; then
	cat >>$lx_rc <<EOF
mount -n -tproc none /proc
root=
for o in \`cat /proc/cmdline\` ; do
  case \$o in
    root=*:*) root="\$o" ;;
    root=*) root="\$o" ; no_dhcp=true ;;
  esac
done
# run dhcp
if test -z "\$no_dhcp" ; then
    dhcp_mode=1
    rootdev=
    # ifconfig lo 127.0.0.1 netmask 255.0.0.0 broadcast 127.255.255.255 up
    # portmap
    echo "running dhcpcd on interface $dhcp_interface"
    dhcpcd -R -Y -N -t 100000000 $dhcp_interface
    test -s /var/lib/dhcpcd/dhcpcd-$dhcp_interface.info || {
	echo "no response from dhcp server."
	echo 256 > /proc/sys/kernel/real-root-dev
	exit 0
    }
    . /var/lib/dhcpcd/dhcpcd-$dhcp_interface.info
    killall -9 dhcpcd
    if test -n "\$DNS" ; then
	oifs="\$IFS"
	IFS=","
	for ns in \$DNS ; do
	    echo "nameserver \$ns" >> /etc/resolv.conf
	done
	IFS="\$oifs"
	test -n "\$DOMAIN" && echo "search \$DOMAIN" >> /etc/resolv.conf
	echo 'hosts: dns' > /etc/nsswitch.conf
    fi
fi
if test -z "\$root" ; then
    if test -z "\$ROOTPATH" ; then
	echo "no root= kernel option given and no rootpath set by the dhcp server."
	echo 256 > /proc/sys/kernel/real-root-dev
	exit 0
    fi
    if test -n "\$DHCPSIADDR" ; then
	rootdev="\$DHCPSIADDR:\$ROOTPATH"
    elif test -n "\$DHCPSNAME" ; then
	rootdev="\$DHCPSNAME:\$ROOTPATH"
    else
	echo "no root= kernel option given and no root server set by the dhcp server."
	echo 256 > /proc/sys/kernel/real-root-dev
	exit 0
    fi
fi
umount -n /proc

EOF
    fi

    if [ "$has_jfs" -a -n "$rootdev" ] ; then
	cat >>$lx_rc <<EOF
# check filesystem if it is of type jfs
mount -n -tproc none /proc
test -z "\$dhcp_mode" && fsck -t jfs "$rootdev"
umount -n /proc

EOF
    fi

    if [ "$use_pivot_root" ] ; then
	cat >>$lx_rc <<EOF
# mount root with pivot_root call
opt="-oro"
test -n "\$dhcp_mode" && opt=-oro,nolock
test -z "\$dhcp_mode" && rootdev="$rootdev"
root=
nopivot=
mount -n -tproc none /proc
# bug in some kernels, need cat
for o in \`cat /proc/cmdline\` ; do
  test "\$o" = rw && opt=
  test "\$o" = rw -a -n "\$dhcp_mode" && opt=-onolock
  case \$o in
    root=ROOT=*) root="\$o" ;;
    root=LABEL=*) root="\$o" ;;
    root=*) root="\$o" ; nopivot=1 ;;
  esac
done
if test -n "\$nopivot" -a -z "\$dhcp_mode" ; then
  umount -n /proc
  exit 0
fi

if test -n "\$root" ; then
  # sed free programming
  echo "\$root" > /.root
  oifs="\$IFS"
  IFS="="
  read dummy rootdev < /.root
  IFS="\$oifs"
fi

# tell kernel root is /dev/ram0, prevents remount after initrd
echo 256 > /proc/sys/kernel/real-root-dev
# mount the actual root device below /mnt
echo "Mounting root \$rootdev"
mount -n \$opt \$rootdev /mnt || exit 1
umount -n /proc
# do pivot-root call
cd /mnt
exec <dev/console >dev/console 2>&1
if test -d initrd ; then
   exec pivot_root . initrd
elif test -d mnt ; then
   pivot_root . mnt
   exec bin/umount -n /mnt
else
   pivot_root . tmp
   exec bin/umount -n /tmp
fi

EOF
    fi

    # now create a second initrd with minimal size

    img_size=`expr \`df -k $tmp_mnt | sed '1d' | awk '{print $3}'\` + 2000`
    mkdir $tmp_mnt_small

    dd if=/dev/zero of=$tmp_initrd_small bs=1k count=$img_size 2>/dev/null
    mke2fs -q -F -b 1024 -m 0 -N $image_inodes $tmp_initrd_small 2>/dev/null 1>&2
    tune2fs -i 0 $tmp_initrd_small >/dev/null 2>&1

    mount -t ext2 -oloop $tmp_initrd_small $tmp_mnt_small || {
      error 3 "failed to mount image"
    }
    is_mounted_small=1

    rmdir $tmp_mnt_small/lost+found
    cp -a $tmp_mnt/* $tmp_mnt_small || error 6 "copy big image to small image failed"
    chown -R 0.0 $tmp_mnt

    umount $tmp_mnt_small
    is_mounted_small=

    umount $tmp_mnt
    is_mounted=

    gzip -9 $tmp_initrd_small

    cp -f $tmp_initrd_small.gz $ii || {
      oops 8 "failed to install initrd"
      continue
    }

    if [ -n "$splash" -a -x /bin/splash ] ; then
      for size in ${splash//,/ }; do
	bootsplash_picture="$bootsplash_picture_dir/images/bootsplash-$size.jpg"
	cfgname="$bootsplash_picture_dir/config/bootsplash-$size.cfg"
	echo " - splash picture ($size)"
	if [ ! -r $cfgname ] ; then
	  echo "config file missing ($cfgname)."
	elif [ ! -r $bootsplash_picture ] ; then
	  echo "picture missing ($bootsplash_picture)."
	else
	  /bin/splash -s -f $cfgname >> $ii
	fi
      done
    fi

    clean_up

  else

    echo "no kernel image \"$k\""

  fi

  kernel_idx=$((kernel_idx+1))

done

umount_proc

if [ "$exit_code" = 0 -a -f "$root_dir/etc/lilo.conf" ] ; then
  if grep -q initrd "$root_dir/etc/lilo.conf" ; then
    echo -e "\nIf you're using lilo as bootmanager, you may want to run 'lilo' now.\n"
  fi
fi

if [ "$exit_code" = 0 -a -f "$root_dir/etc/zipl.conf" ] ; then
  echo -e "\nRun zipl now to update the IPL record!\n"
fi

exit $exit_code
